Animation of plots in R can be fairly straightforward. It can also be stunningly complex. We’ll focus on the straightforward ones - you’ll have to wrap your head around some of the lingo, but once you get the drift it’s not that difficult.
We’ll be using gganimate to do our animating. If you
don’t already have this or gifski and av as an
installed library, you’ll want to do that (these are what support the
creation of GIF and movie files respectively. Yet again, we’ll be using
the gapminder dataset.
Load the necessary libraries:
# install.packages(c("gifski", "av", "gganimate"))
library(gapminder)
library(tidyverse)
library(gganimate)
gganimate is built on top of ggplot, so the
general approach is to first get a solid static ggplot visualization
that we can use as our base, and once we have that, we animate it. Let’s
begin with a robust, but completely standard ggplot call:
p1 <- ggplot(gapminder, aes(gdpPercap, lifeExp, size = pop, color = country)) +
geom_point(alpha = 0.7, show.legend = FALSE) +
scale_color_manual(values = country_colors) +
scale_size(range = c(2, 12)) +
scale_x_log10() +
facet_wrap(~continent) +
theme_bw() +
labs(title = "Year: 1952-2007", x = "GPD per capita", y = "Life Expectancy")
print(p1)
To turn it into an animation, we simply add a few functions:
labs function overwrites the previous one, so we
can dynamically display the changing years as the data
points move across the plot. Note the curly brackets enclosing the
variable frame_time that will allow the year to dynamically
display.transition_time function takes in the year variable
as an input and it allows the animated plot to transition frame by frame
as a function of the year variable.ease_aes function takes in linear as an input argument
and it defines how the transition occurs from frame to frame (in this
case, linear). More on this below…animate function.anim_save function allows the animated plot to be
rendered to a .GIF file.p2 <- p1 +
labs(title = "Year: {frame_time}", x = "GDP per capita", y = "Life Expectancy") +
transition_time(year) +
ease_aes('linear')
animate(p2)
anim_save("gapminder1.gif")
The ease_aes function defines how a value changes to
another value during it’s animated transition from one state to another.
Will it progress linearly, or maybe start slowly and then build up
momentum? Your ease function will determine that. Here are the available
options and what they do:
Ok, you’re thinking…I have no idea what any of that actually means. Neither do I really. So just use this resource that can give you a sense of how each of these easing functions behave: https://easings.net/
There are also modifiers you can apply to these ease functions: -in The easing function is applied as-is -out The easing function is applied in reverse -in-out The first half of the transition it is applied as-is, while in the last half it is reversed
I wouldn’t overthink this - just choose something that looks good to you!
We can use shadow_wake() to draw a small wake after the
data by showing the latest frames up to the current. You can choose to
gradually diminish the size and/or opacity of the shadow. The length of
the wake is not given in absolute frames, it is given as a proportion of
the total length of the animation, so the example below gives us a wake
of points from the last 30% of frames. The alpha value is set here to
FALSE so that the shadows are not transparent, but you can either set
that to TRUE or a numeric (0-1) indicating what the alpha should be.
Notice that we are simply layering on a shadow_wake()
function call to the previously saved p2 object.
p3 <- p2 +
shadow_wake(wake_length = 0.3, alpha = FALSE)
animate(p3)
anim_save("gapminder2.gif")
Alternatively we can use shadow_trail() to show the
original data as a trail. The parameter distance means the
animation will keep the points from 30% of the frames, spaced as evenly
as possible.
p4 <- p2 +
shadow_trail(distance = 0.3)
animate(p4)
anim_save("gapminder3.gif")
We can also use gganimate to reveal data along a specific dimension. This is most useful for time series data in which you can show the change over time. Below we’ve created a standard line plot of lifeExp by country, filtered to just show countries in Asia.
p5 <- ggplot(gapminder %>% filter(continent == "Asia"), aes(year, lifeExp, color = country)) +
geom_line(show.legend = FALSE) +
labs(title = "Life Expectancy Over Time - Asian Continent")
p5
We can then call transition_reveal to let the data
gradually appear, by year. The geom_point call means that
as it appears it shows a point.
p6 <- p5 +
geom_point(show.legend = FALSE) +
transition_reveal(year)
animate(p6)
anim_save("gapminder4.gif")
There may also be times when animating bar charts could be useful.
Here we create a bar chart and then add an additional aesthetic called
transition_states that provides a frame variable of year.
For each value of the variable, a step on the chart will be drawn. The
transition_length tells us how long the transition should
be and the state_length is how long it rests at a
particular state. Here they are set to be equal. Notice that we’ve also
changed up our ease_aes function to “sine-in-out” (not for
any particular reason).
p7 <- gapminder %>%
group_by(year, continent) %>%
summarize(cont_pop = sum(pop)) %>%
ggplot(aes(continent, cont_pop, fill = continent)) +
geom_bar(stat = "identity") +
transition_states(year, transition_length = 2, state_length = 2) +
ease_aes('sine-in-out') +
labs(title = "Population in {closest_state}")
animate(p7)
anim_save("gapminder5.gif")
We could just as easily have used the transition_time
function here since we are using time as our animating variable. If we
did that, our label would instead reference {frame_time}
instead of {closest_state} and we would NOT have control
over the transition length or state length. We wouldn’t have that
control because for transition_time gganimate treats the
time variable as continuous, so the transition length is based on the
actual values. Notice the difference between the two!
p8 <- gapminder %>%
group_by(year, continent) %>%
summarize(cont_pop = sum(pop)) %>%
ggplot(aes(continent, cont_pop, fill = continent)) +
geom_bar(stat = "identity") +
transition_time(year) +
ease_aes('sine-in-out') +
labs(title = "Population in {frame_time}")
## `summarise()` has grouped output by 'year'. You can override using the
## `.groups` argument.
animate(p8)
anim_save("gapminder6.gif")
Leaflet is a powerful open-source JavaScript library for building interactive maps in HTML.
The architecture is very similar to ggplot2, but instead of putting data-based layers on top of a static map, leaflet allows you to put data-based layers on top of an interactive map.
A leaflet map widget is created with the leaflet()
command. We then add layers to the widget. The first layer that we will
add is a tile layer containing all of the static map information, which
by default comes from OpenStreetMap. The second layer we will add here
is a marker, which designates a point location. Notice how the
addMarkers() function can take a data argument, just like a
geom_*() layer in ggplot2 would.
Below, we get started by creating a data frame containing the White
House and then call tidygeocoder’s geocode function to get
lat and long. After loading the leaflet library, we create a new object
by calling leaflet to create a widget,
add_tiles and finally addMarkers in which we
designate the data set.
white_house <- tibble(
address = "The White House, Washington, DC"
) %>%
tidygeocoder::geocode(address, method = "osm")
library(leaflet)
white_house_map <- leaflet() %>%
addTiles() %>%
addMarkers(data = white_house)
white_house_map
You can scroll and zoom at will!
You can also add a pop-up to provide more information about a particular location. Notice how we only need to call the previously saved leaflet map and then add a Popup layer to it.
white_house <- white_house %>%
mutate(title = "The White House",
street_address = "1600 Pennsylvania Ave")
white_house_map %>%
addPopups(data = white_house,
popup = ~paste0("<b>", title, "</b></br>", street_address))
There are several different providers of tiles. Below we’ll demonstrate two others, and we’ll also see how we can set a specific view and zoom level by giving it a lat and long and designating the zoom level desired.
# Background 1: NASA
leaflet() %>%
addTiles() %>%
setView(lng = 2.34, lat = 48.85, zoom = 5) %>%
addProviderTiles("NASAGIBS.ViirsEarthAtNight2012")
# Background 2: World Imagery
leaflet() %>%
addTiles() %>%
setView(lng = 2.34, lat = 48.85, zoom = 3) %>%
addProviderTiles("Esri.WorldImagery")
Here are some especially popular provider tiles that Leaflet provides:
And this is a great website where you can preview all the available ones.
You can create choropleth maps in Leaflet. Here we’ll be showing 2016
House election results in NC using the fec16 package that
has detailed election results. We call their results_house
dataset, do some clean up and then join it into their
candidates dataset. From there we filter to North Carolina,
group by the district and create some summary variables for each CD.
library(socviz)
nc_results <- county_data %>% # built in soviz data
select(state, id, name, per_gop_2016) %>%
filter(state == "NC",
name != "34")
nc_results
## state id name per_gop_2016
## 1 NC 37001 Alamance County 0.5520184
## 2 NC 37003 Alexander County 0.7676420
## 3 NC 37005 Alleghany County 0.7266974
## 4 NC 37007 Anson County 0.4310179
## 5 NC 37009 Ashe County 0.7107143
## 6 NC 37011 Avery County 0.7724566
## 7 NC 37013 Beaufort County 0.6135006
## 8 NC 37015 Bertie County 0.3705757
## 9 NC 37017 Bladen County 0.5406212
## 10 NC 37019 Brunswick County 0.6310311
## 11 NC 37021 Buncombe County 0.4114210
## 12 NC 37023 Burke County 0.6839099
## 13 NC 37025 Cabarrus County 0.5848663
## 14 NC 37027 Caldwell County 0.7412930
## 15 NC 37029 Camden County 0.7141122
## 16 NC 37031 Carteret County 0.7104201
## 17 NC 37033 Caswell County 0.5475987
## 18 NC 37035 Catawba County 0.6763104
## 19 NC 37037 Chatham County 0.4353122
## 20 NC 37039 Cherokee County 0.7727994
## 21 NC 37041 Chowan County 0.5603545
## 22 NC 37043 Clay County 0.7468139
## 23 NC 37045 Cleveland County 0.6433151
## 24 NC 37047 Columbus County 0.6039963
## 25 NC 37049 Craven County 0.5960503
## 26 NC 37051 Cumberland County 0.4066896
## 27 NC 37053 Currituck County 0.7300974
## 28 NC 37055 Dare County 0.5935609
## 29 NC 37057 Davidson County 0.7341730
## 30 NC 37059 Davie County 0.7260890
## 31 NC 37061 Duplin County 0.5898257
## 32 NC 37063 Durham County 0.1851896
## 33 NC 37065 Edgecombe County 0.3333874
## 34 NC 37067 Forsyth County 0.4335600
## 35 NC 37069 Franklin County 0.5457829
## 36 NC 37071 Gaston County 0.6478940
## 37 NC 37073 Gates County 0.5350976
## 38 NC 37075 Graham County 0.7962873
## 39 NC 37077 Granville County 0.5014859
## 40 NC 37079 Greene County 0.5438662
## 41 NC 37081 Guilford County 0.3866165
## 42 NC 37083 Halifax County 0.3598730
## 43 NC 37085 Harnett County 0.6067846
## 44 NC 37087 Haywood County 0.6248839
## 45 NC 37089 Henderson County 0.6255061
## 46 NC 37091 Hertford County 0.3050495
## 47 NC 37093 Hoke County 0.4301003
## 48 NC 37095 Hyde County 0.5609327
## 49 NC 37097 Iredell County 0.6709527
## 50 NC 37099 Jackson County 0.5391024
## 51 NC 37101 Johnston County 0.6396225
## 52 NC 37103 Jones County 0.5836475
## 53 NC 37105 Lee County 0.5521559
## 54 NC 37107 Lenoir County 0.5236863
## 55 NC 37109 Lincoln County 0.7263302
## 56 NC 37111 McDowell County 0.7422918
## 57 NC 37113 Macon County 0.6942201
## 58 NC 37115 Madison County 0.6141711
## 59 NC 37117 Martin County 0.4956126
## 60 NC 37119 Mecklenburg County 0.3341092
## 61 NC 37121 Mitchell County 0.7832159
## 62 NC 37123 Montgomery County 0.6175212
## 63 NC 37125 Moore County 0.6340426
## 64 NC 37127 Nash County 0.4934013
## 65 NC 37129 New Hanover County 0.5027268
## 66 NC 37131 Northampton County 0.3643069
## 67 NC 37133 Onslow County 0.6564193
## 68 NC 37135 Orange County 0.2301516
## 69 NC 37137 Pamlico County 0.6238925
## 70 NC 37139 Pasquotank County 0.4764207
## 71 NC 37141 Pender County 0.6396646
## 72 NC 37143 Perquimans County 0.6282032
## 73 NC 37145 Person County 0.5758690
## 74 NC 37147 Pitt County 0.4496448
## 75 NC 37149 Polk County 0.6283689
## 76 NC 37151 Randolph County 0.7727108
## 77 NC 37153 Richmond County 0.5421251
## 78 NC 37155 Robeson County 0.5143712
## 79 NC 37157 Rockingham County 0.6396046
## 80 NC 37159 Rowan County 0.6719934
## 81 NC 37161 Rutherford County 0.7288671
## 82 NC 37163 Sampson County 0.5757469
## 83 NC 37165 Scotland County 0.4520119
## 84 NC 37167 Stanly County 0.7398051
## 85 NC 37169 Stokes County 0.7653052
## 86 NC 37171 Surry County 0.7420333
## 87 NC 37173 Swain County 0.5946172
## 88 NC 37175 Transylvania County 0.5986812
## 89 NC 37177 Tyrrell County 0.5694118
## 90 NC 37179 Union County 0.6396482
## 91 NC 37181 Vance County 0.3695982
## 92 NC 37183 Wake County 0.3789232
## 93 NC 37185 Warren County 0.3261879
## 94 NC 37187 Washington County 0.4186427
## 95 NC 37189 Watauga County 0.4699851
## 96 NC 37191 Wayne County 0.5491329
## 97 NC 37193 Wilkes County 0.7655622
## 98 NC 37195 Wilson County 0.4631181
## 99 NC 37197 Yadkin County 0.7962536
## 100 NC 37199 Yancey County 0.6491639
Now we need a NC counties shapefile. Remember that we can go to the
tigris package here for this. We also need to load up the
sf library so we can work with sf data.
library(sf)
library(tigris)
nc_map <- counties(state = c("NC"))
##
|
| | 0%
|
| | 1%
|
|= | 1%
|
|= | 2%
|
|== | 2%
|
|== | 3%
|
|== | 4%
|
|=== | 4%
|
|=== | 5%
|
|==== | 5%
|
|==== | 6%
|
|===== | 6%
|
|===== | 7%
|
|===== | 8%
|
|====== | 8%
|
|====== | 9%
|
|======= | 9%
|
|======= | 10%
|
|======= | 11%
|
|======== | 11%
|
|======== | 12%
|
|========= | 13%
|
|========= | 14%
|
|========== | 14%
|
|========== | 15%
|
|=========== | 15%
|
|=========== | 16%
|
|============ | 16%
|
|============ | 17%
|
|============ | 18%
|
|============= | 18%
|
|============= | 19%
|
|============== | 19%
|
|============== | 20%
|
|============== | 21%
|
|=============== | 21%
|
|=============== | 22%
|
|================ | 22%
|
|================ | 23%
|
|================= | 24%
|
|================= | 25%
|
|================== | 25%
|
|================== | 26%
|
|=================== | 26%
|
|=================== | 27%
|
|=================== | 28%
|
|==================== | 28%
|
|==================== | 29%
|
|===================== | 29%
|
|===================== | 30%
|
|====================== | 31%
|
|====================== | 32%
|
|======================= | 32%
|
|======================= | 33%
|
|======================== | 34%
|
|======================== | 35%
|
|========================= | 35%
|
|========================= | 36%
|
|========================== | 36%
|
|========================== | 37%
|
|========================== | 38%
|
|=========================== | 38%
|
|=========================== | 39%
|
|============================ | 39%
|
|============================ | 40%
|
|============================ | 41%
|
|============================= | 41%
|
|============================= | 42%
|
|============================== | 42%
|
|============================== | 43%
|
|============================== | 44%
|
|=============================== | 44%
|
|=============================== | 45%
|
|================================ | 45%
|
|================================ | 46%
|
|================================= | 46%
|
|================================= | 47%
|
|================================= | 48%
|
|================================== | 49%
|
|=================================== | 49%
|
|=================================== | 50%
|
|==================================== | 51%
|
|==================================== | 52%
|
|===================================== | 52%
|
|===================================== | 53%
|
|===================================== | 54%
|
|====================================== | 54%
|
|====================================== | 55%
|
|======================================= | 55%
|
|======================================= | 56%
|
|======================================== | 56%
|
|======================================== | 57%
|
|======================================== | 58%
|
|========================================= | 58%
|
|========================================= | 59%
|
|========================================== | 59%
|
|========================================== | 60%
|
|========================================== | 61%
|
|=========================================== | 61%
|
|=========================================== | 62%
|
|============================================ | 63%
|
|============================================= | 64%
|
|============================================= | 65%
|
|============================================== | 65%
|
|============================================== | 66%
|
|=============================================== | 66%
|
|=============================================== | 67%
|
|=============================================== | 68%
|
|================================================ | 68%
|
|================================================ | 69%
|
|================================================= | 69%
|
|================================================= | 70%
|
|================================================= | 71%
|
|================================================== | 71%
|
|================================================== | 72%
|
|=================================================== | 72%
|
|=================================================== | 73%
|
|=================================================== | 74%
|
|==================================================== | 74%
|
|==================================================== | 75%
|
|===================================================== | 75%
|
|===================================================== | 76%
|
|====================================================== | 76%
|
|====================================================== | 77%
|
|====================================================== | 78%
|
|======================================================= | 78%
|
|======================================================= | 79%
|
|======================================================== | 79%
|
|======================================================== | 80%
|
|======================================================== | 81%
|
|========================================================= | 81%
|
|========================================================= | 82%
|
|========================================================== | 82%
|
|========================================================== | 83%
|
|========================================================== | 84%
|
|=========================================================== | 84%
|
|=========================================================== | 85%
|
|============================================================ | 85%
|
|============================================================ | 86%
|
|============================================================= | 86%
|
|============================================================= | 87%
|
|============================================================= | 88%
|
|============================================================== | 88%
|
|============================================================== | 89%
|
|=============================================================== | 89%
|
|=============================================================== | 90%
|
|=============================================================== | 91%
|
|================================================================ | 91%
|
|================================================================ | 92%
|
|================================================================= | 92%
|
|================================================================= | 93%
|
|================================================================= | 94%
|
|================================================================== | 94%
|
|================================================================== | 95%
|
|=================================================================== | 95%
|
|=================================================================== | 96%
|
|==================================================================== | 96%
|
|==================================================================== | 97%
|
|==================================================================== | 98%
|
|===================================================================== | 98%
|
|===================================================================== | 99%
|
|======================================================================| 99%
|
|======================================================================| 100%
nc_map
## Simple feature collection with 100 features and 17 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: -84.32182 ymin: 33.75288 xmax: -75.40012 ymax: 36.58814
## Geodetic CRS: NAD83
## First 10 features:
## STATEFP COUNTYFP COUNTYNS GEOID NAME NAMELSAD LSAD CLASSFP MTFCC
## 24 37 037 01008544 37037 Chatham Chatham County 06 H1 G4020
## 60 37 001 01008531 37001 Alamance Alamance County 06 H1 G4020
## 92 37 057 01008548 37057 Davidson Davidson County 06 H1 G4020
## 183 37 069 01008553 37069 Franklin Franklin County 06 H1 G4020
## 220 37 155 01026130 37155 Robeson Robeson County 06 H1 G4020
## 225 37 109 01008569 37109 Lincoln Lincoln County 06 H1 G4020
## 234 37 027 01008541 37027 Caldwell Caldwell County 06 H1 G4020
## 263 37 063 01008550 37063 Durham Durham County 06 H1 G4020
## 292 37 145 01008577 37145 Person Person County 06 H1 G4020
## 306 37 115 01025834 37115 Madison Madison County 06 H1 G4020
## CSAFP CBSAFP METDIVFP FUNCSTAT ALAND AWATER INTPTLAT INTPTLON
## 24 450 20500 <NA> A 1765540362 70582736 +35.7049939 -079.2514542
## 60 268 15500 <NA> A 1096736059 27940532 +36.0439535 -079.4005733
## 92 268 49180 <NA> A 1432728609 37604804 +35.7951312 -080.2071070
## 183 450 39580 <NA> A 1273761673 7173998 +36.0882406 -078.2830903
## 220 246 31300 <NA> A 2453481924 5076395 +34.6392096 -079.1008811
## 225 172 16740 <NA> A 766239897 23350160 +35.4884909 -081.2268928
## 234 <NA> 25860 <NA> A 1222184252 7052759 +35.9663959 -081.5125404
## 263 450 20500 <NA> A 742303736 29156730 +36.0338282 -078.8781246
## 292 450 20500 <NA> A 1016154889 31205409 +36.3863559 -078.9656305
## 306 120 11700 <NA> A 1164498325 4840167 +35.8642058 -082.7126309
## geometry
## 24 MULTIPOLYGON (((-79.24113 3...
## 60 MULTIPOLYGON (((-79.43277 3...
## 92 MULTIPOLYGON (((-80.06476 3...
## 183 MULTIPOLYGON (((-78.11729 3...
## 220 MULTIPOLYGON (((-79.12835 3...
## 225 MULTIPOLYGON (((-81.08133 3...
## 234 MULTIPOLYGON (((-81.33647 3...
## 263 MULTIPOLYGON (((-78.80676 3...
## 292 MULTIPOLYGON (((-78.7998 36...
## 306 MULTIPOLYGON (((-82.6677 35...
We need to merge in the election data with the shape file. The
nc_results data has an id field that 5
characters long, everyone starting with 37. The nc_map file
has a STATEFP 2 character variable that is always 37, and
COUNTYFP that is three characters long. These are the FIPS
codes that are the standardized ids for US states and counties. So in
order to merge the nc_shp polygons with the nc_results election data
frame we will need to concatenate STATEFP and
COUNTYFP into a new variable named id, then
join the two datasets together.
nc_merged <- nc_map %>%
mutate(id = str_c(STATEFP, COUNTYFP)) %>% # creating a new ID that puts the state and county one together
left_join(nc_results, by = "id")
glimpse(nc_merged)
## Rows: 100
## Columns: 22
## $ STATEFP <chr> "37", "37", "37", "37", "37", "37", "37", "37", "37", "37…
## $ COUNTYFP <chr> "037", "001", "057", "069", "155", "109", "027", "063", "…
## $ COUNTYNS <chr> "01008544", "01008531", "01008548", "01008553", "01026130…
## $ GEOID <chr> "37037", "37001", "37057", "37069", "37155", "37109", "37…
## $ NAME <chr> "Chatham", "Alamance", "Davidson", "Franklin", "Robeson",…
## $ NAMELSAD <chr> "Chatham County", "Alamance County", "Davidson County", "…
## $ LSAD <chr> "06", "06", "06", "06", "06", "06", "06", "06", "06", "06…
## $ CLASSFP <chr> "H1", "H1", "H1", "H1", "H1", "H1", "H1", "H1", "H1", "H1…
## $ MTFCC <chr> "G4020", "G4020", "G4020", "G4020", "G4020", "G4020", "G4…
## $ CSAFP <chr> "450", "268", "268", "450", "246", "172", NA, "450", "450…
## $ CBSAFP <chr> "20500", "15500", "49180", "39580", "31300", "16740", "25…
## $ METDIVFP <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
## $ FUNCSTAT <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A…
## $ ALAND <dbl> 1765540362, 1096736059, 1432728609, 1273761673, 245348192…
## $ AWATER <dbl> 70582736, 27940532, 37604804, 7173998, 5076395, 23350160,…
## $ INTPTLAT <chr> "+35.7049939", "+36.0439535", "+35.7951312", "+36.0882406…
## $ INTPTLON <chr> "-079.2514542", "-079.4005733", "-080.2071070", "-078.283…
## $ id <chr> "37037", "37001", "37057", "37069", "37155", "37109", "37…
## $ state <fct> NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, N…
## $ name <chr> "Chatham County", "Alamance County", "Davidson County", "…
## $ per_gop_2016 <dbl> 0.4353122, 0.5520184, 0.7341730, 0.5457829, 0.5143712, 0.…
## $ geometry <MULTIPOLYGON [°]> MULTIPOLYGON (((-79.24113 3..., MULTIPOLYGON…
We can then use Leaflet. First we will define a color palette over
the values [0,1] that ranges from red to blue. According to the
documentation, colorNumeric():
Conveniently maps data values (numeric or factor/character) to colors according to a given palette, which can be provided in a variety of formats.
The palette argument can be any of the following:
The domain parameter tells it the possible values that
can be mapped. Once created it, you’ll see that it simply returns a
function.
pal <- colorNumeric(palette = "RdBu", domain = c(0,1))
pal
## function (x)
## {
## if (length(x) == 0 || all(is.na(x))) {
## return(pf(x))
## }
## if (is.null(rng))
## rng <- range(x, na.rm = TRUE)
## rescaled <- scales::rescale(x, from = rng)
## if (any(rescaled < 0 | rescaled > 1, na.rm = TRUE))
## warning("Some values were outside the color scale and will be treated as NA")
## if (reverse) {
## rescaled <- 1 - rescaled
## }
## pf(rescaled)
## }
## <bytecode: 0x12db4ce28>
## <environment: 0x12db1e6b0>
## attr(,"colorType")
## [1] "numeric"
## attr(,"colorArgs")
## attr(,"colorArgs")$na.color
## [1] "#808080"
To make the plot in Leaflet, we have to add the tiles, and then the polygons defined by the sf object nc_merged. Since it is already an SF object, we do not need to give it any explicit polygon arguments in terms of X and Y. Instead, we need to manipulate the weight, fillOpacity, and color, while also designating the text of the popup.
</br> because this is
an interactive viz rendered in HTML.leaflet_nc <- leaflet(nc_merged) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(
weight = 1,
color = "grey",
fillColor = ~pal(1-per_gop_2016),
fillOpacity = 0.9,
popup = ~str_c("<b>", name, "</b></br>", "GOP = ", round(per_gop_2016 * 100, 0), "%")) %>%
setView(lng = -80, lat = 35, zoom = 7)
leaflet_nc
We might want to add a state border here. To do so, we’ll need to get
a state sf object using tigris, and then we simply add
another addPolygons function call, this time pointing it
specifically at the state sf object. We can set some options like the
weight and color of the border, but the most important thing to do here
is to tell it NOT to fill the object because that would obstruct our
county fills.
nc_state_map <- states() %>%
filter(NAME == "North Carolina")
## Retrieving data for the year 2021
##
|
| | 0%
|
|= | 1%
|
|== | 3%
|
|=== | 4%
|
|==== | 6%
|
|===== | 7%
|
|===== | 8%
|
|====== | 8%
|
|====== | 9%
|
|======= | 10%
|
|======== | 11%
|
|======== | 12%
|
|========= | 12%
|
|========= | 13%
|
|=========== | 16%
|
|============ | 17%
|
|============ | 18%
|
|============= | 18%
|
|============= | 19%
|
|============== | 19%
|
|============== | 20%
|
|============== | 21%
|
|=============== | 22%
|
|================ | 22%
|
|================ | 23%
|
|================= | 24%
|
|================= | 25%
|
|================== | 25%
|
|================== | 26%
|
|=================== | 26%
|
|=================== | 27%
|
|=================== | 28%
|
|==================== | 28%
|
|==================== | 29%
|
|===================== | 30%
|
|===================== | 31%
|
|====================== | 31%
|
|======================= | 32%
|
|======================= | 33%
|
|======================== | 34%
|
|======================== | 35%
|
|========================= | 35%
|
|========================= | 36%
|
|========================== | 36%
|
|========================== | 37%
|
|========================== | 38%
|
|=========================== | 38%
|
|=========================== | 39%
|
|============================ | 40%
|
|============================= | 42%
|
|============================== | 43%
|
|============================== | 44%
|
|=============================== | 44%
|
|=============================== | 45%
|
|================================ | 45%
|
|================================ | 46%
|
|================================= | 47%
|
|================================== | 48%
|
|================================== | 49%
|
|=================================== | 50%
|
|==================================== | 51%
|
|==================================== | 52%
|
|===================================== | 52%
|
|===================================== | 53%
|
|====================================== | 54%
|
|====================================== | 55%
|
|======================================= | 56%
|
|======================================== | 57%
|
|======================================== | 58%
|
|========================================= | 58%
|
|========================================= | 59%
|
|========================================== | 59%
|
|========================================== | 60%
|
|=========================================== | 61%
|
|============================================ | 62%
|
|============================================ | 63%
|
|============================================= | 64%
|
|============================================== | 66%
|
|================================================ | 68%
|
|================================================ | 69%
|
|================================================= | 70%
|
|================================================= | 71%
|
|================================================== | 71%
|
|================================================== | 72%
|
|=================================================== | 73%
|
|==================================================== | 74%
|
|===================================================== | 76%
|
|====================================================== | 77%
|
|======================================================= | 78%
|
|======================================================= | 79%
|
|======================================================== | 80%
|
|======================================================== | 81%
|
|========================================================= | 81%
|
|========================================================= | 82%
|
|========================================================== | 83%
|
|=========================================================== | 84%
|
|=========================================================== | 85%
|
|============================================================ | 85%
|
|================================================================== | 94%
|
|=================================================================== | 95%
|
|=================================================================== | 96%
|
|==================================================================== | 96%
|
|==================================================================== | 97%
|
|===================================================================== | 98%
|
|===================================================================== | 99%
|
|======================================================================| 100%
leaflet_nc <- leaflet(nc_merged) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(
weight = 1,
color = "grey",
fillColor = ~pal(1-per_gop_2016),
fillOpacity = 0.9,
popup = ~str_c("<b>", name, "</b></br>", "GOP = ", round(per_gop_2016 * 100, 0), "%")) %>%
addPolygons(
data = nc_state_map,
weight = 2,
color = "#000000",
fill = FALSE) %>% # Do not fill the inside of the state; only draw the border
setView(lng = -80, lat = 35, zoom = 7)
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
## Warning: sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
## Need '+proj=longlat +datum=WGS84'
leaflet_nc